#include <system.h>
#include <pio.h>
#include <std.h>
#include <error.h>
#include <memory.h>
#include <asm.h>
#include <irq.h>
#include <timer.h>
#include <sched.h>

/**********************Kernel Function File*********************timer.h*/

#define SYS_CLOCK_INTERRUPT 0
static volatile unsigned long live=0;
static volatile unsigned long timer_count=0;

struct timer_call *volatile head;


u32 i=0;
void timer()
{
	struct timer_call *temp;
	for(temp=head->next;temp!=NULL;temp=temp->next)	{
		temp->resolution--;
		if(temp->resolution<=0) {
			temp->resolution=0;
			if(temp->flags==TIMER_ASYNC_THREAD)	{
				thread_send_signal(temp->sig_pid,THREAD_SIG_TIMER);
			} else if(temp->flags==TIMER_ASYNC_FUNCTION) {
				function_send_signal(temp->signal_fn,THREAD_SIG_TIMER);
			} else
				(temp->entry)();
		}
	}
	live=0;
}

void print_list()
{
	struct timer_call *temp;
	for(temp=head->next;temp!=NULL;temp=temp->next)	{
		printk("\ntimer %x",temp);
	}
}


int add_timer(struct timer_call *t)
{
	t->resolution=(SYSTEM_SCHEDULE_CLOCK_SPEED*t->ms)/1000;
	t->next=NULL;
	struct timer_call *temp;
	for(temp=head;temp->next!=NULL;temp=temp->next);
	kernel_lock();
	temp->next=t;
	kernel_unlock();
	return NULL;
}

int remove_timer(struct timer_call *t)
{
	struct timer_call *temp;
	for(temp=head;temp->next!=t && temp;temp=temp->next);
	if(!temp)
		return NULL;
	kernel_lock();
	temp->next=t->next;
	kernel_unlock();
	return NULL;
}

int update_timer(struct timer_call *t)
{
	t->resolution=(SYSTEM_SCHEDULE_CLOCK_SPEED*t->ms)/1000;
	return NULL;
}


static volatile unsigned long speed_u,speed_m;

unsigned long proc_speed()
{
	unsigned long x,y,speed=0;
	if((!_interrupt_flag()) || is_irq(0))
		stop("proc_speed:Unexpected irq state");
	live=1;
	while(live);
	live=1;
	x=_SYSTEM_READ_TIMER();
	while(live);
	y=_SYSTEM_READ_TIMER();
	speed_m=((y-x)*SYSTEM_SCHEDULE_CLOCK_SPEED)/1000;
	speed_u=((y-x)*SYSTEM_SCHEDULE_CLOCK_SPEED)/1000000;
	return speed;
}

unsigned long cpuspeed2()
{
	unsigned long stsc,etsc,ticks,speed;
	unsigned char hi,lo;
	int i;
	outb(0x43,0x34);   // set PIT channel 0 to single-shot mode
	outb(0x40,0);
	outb(0x40,0);      // program the counter will be 0x10000 - n after n ticks
	stsc=_SYSTEM_READ_TIMER();
	for (i=0x1000;i>0;i--);
	etsc=_SYSTEM_READ_TIMER();
	outb(0x43,0x04);   // read PIT counter command ??
	lo=inb(0x40);
	hi=inb(0x40);
	ticks=(0x10000 - (hi*256+lo));
	speed=(etsc-stsc)*1193180 / ticks;
	setclock(SYSTEM_SCHEDULE_CLOCK_SPEED);
	return (speed/1000);
}

unsigned int read_timer()
{
	unsigned int val=0;
	outb(0x43,0x00);
	val|=(unsigned char)inb(0x40);
	val|=(((unsigned char)inb(0x40))<<8);
	return val;
}

void mdelay(unsigned long count)
{
	register unsigned long x,y;
	while(--count>0)	{
		x=_SYSTEM_READ_TIMER();
		y=x;
		while((y-x)<=speed_m)	{
			y=_SYSTEM_READ_TIMER();
		}
	}
}

void clkdelay(unsigned long count)
{
	register unsigned long x,y;
	x=_SYSTEM_READ_TIMER();
	y=_SYSTEM_READ_TIMER();
	while((y-x)<count)	{
		y=_SYSTEM_READ_TIMER();
	}
}

void udelay(unsigned long count)
{
	register unsigned long x,y;
	while(--count>0)	{
		x=_SYSTEM_READ_TIMER();
		y=x;
		while((y-x)<=speed_u)	{
			y=_SYSTEM_READ_TIMER();
		}
	}
}

unsigned long cpu_ms()
{
	return speed_m;
}

void init_timer()
{
	printk("\nTimers initiating"); 
	request_irq(NULL,0,timer);
	create_head(struct timer_call,head);
	head->next=NULL;
	head->entry=NULL;
	head->resolution=NULL;
	setclock(SYSTEM_SCHEDULE_CLOCK_SPEED);
	enable_irq(0);
	proc_speed();
	if(speed_u==0)	{
		printk(" speed_u corrected.");
		speed_u=100;
	}
	printk(" speed_m:%d speed_u:%d",speed_m,speed_u);
}
